/***************************************** 
 * Desc: 面板基类（需要挂载到对象上）,默认不可交互
 * @Author: GSan
 * @Email: 2087653648@qq.com
 * CreateDate: 2020-07-09 11:21:45
*****************************************/

using Common.UGUI.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Common.UGUI.View {

    [RequireComponent(typeof(Image))]
    public class UGUIPanel : UGUIView, IPointerDownHandler, IDragHandler, IPointerUpHandler, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler {

        #region 域

        public virtual bool IsInteractable {
            get {
                return _isInteractable;
            }
            set {
                SetIsInteractable(value);
            }
        }

        public Image Image {

            get { 

                if(_image == null) {

                    _image = GameObject.GetComponent<Image>();
                }

                return _image;
            }
        }

        /// <summary>
        /// 所有注册的按下回调名字
        /// </summary>
        public string[] PointerDownCallbackNameArray { 
            get {
                return _pointerDownCallbackDict.Keys.ToArray();
            }
        }
        /// <summary>
        /// 所有注册的拖动回调名字
        /// </summary>
        public string[] PointerDragCallbackNameArray {
            get {
                return _pointerDragCallbackDict.Keys.ToArray();
            }
        }
        /// <summary>
        /// 所有注册的抬起回调名字
        /// </summary>
        public string[] PointerUpCallbackNameArray {
            get {
                return _pointerUpCallbackDict.Keys.ToArray();
            }
        }
        /// <summary>
        /// 所有注册的点击回调名字
        /// </summary>
        public string[] PointerClickCallbackNameArray {
            get {
                return _pointerClickCallbackDict.Keys.ToArray();
            }
        }
        /// <summary>
        /// 所有注册的进入回调名字
        /// </summary>
        public string[] PointerEnterCallbackNameArray {
            get {
                return _pointerEnterCallbackDict.Keys.ToArray();
            }
        }
        /// <summary>
        /// 所有注册的离开回调名字
        /// </summary>
        public string[] PointerExitClickCallbackNameArray {
            get {
                return _pointerExitCallbackDict.Keys.ToArray();
            }
        }

        private Image _image = null;

        [SerializeField]
        protected bool _isInteractable = false;

        /// <summary>
        /// 图片的原始缩放
        /// </summary>
        protected Vector3 _originalScale = Vector3.one;

        protected Dictionary<string, Action<PointerEventData>> _pointerDownCallbackDict = new Dictionary<string, Action<PointerEventData>>();
        protected Dictionary<string, Action<PointerEventData>> _pointerDragCallbackDict = new Dictionary<string, Action<PointerEventData>>();
        protected Dictionary<string, Action<PointerEventData>> _pointerUpCallbackDict = new Dictionary<string, Action<PointerEventData>>();
        protected Dictionary<string, Action<PointerEventData>> _pointerClickCallbackDict = new Dictionary<string, Action<PointerEventData>>();
        protected Dictionary<string, Action<PointerEventData>> _pointerEnterCallbackDict = new Dictionary<string, Action<PointerEventData>>();
        protected Dictionary<string, Action<PointerEventData>> _pointerExitCallbackDict = new Dictionary<string, Action<PointerEventData>>();

        #endregion

        #region Unity生命周期

        protected override void OnAwake() {

            _image = GameObject.GetComponent<Image>();
            _originalScale = _image.rectTransform.localScale;
        }

        #endregion

        #region 公用UI接口

        /// <summary>
        /// 设置是否可以交互（点击事件）
        /// </summary>
        public virtual void SetIsInteractable(bool isInteractable) {

            _isInteractable = isInteractable;

            Image.raycastTarget = isInteractable;
        }

        /// <summary>
        /// 设置图片
        /// </summary>
        public void SetTexture(Texture2D newTexture) {

            Image.sprite = Sprite.Create(newTexture, new Rect(0, 0, newTexture.width, newTexture.height), new Vector2(0.5f, 0.5f));
        }

        /// <summary>
        /// 设置Panel颜色
        /// </summary>
        public virtual void SetColor(Color color) {

            Image.color = color;
        }

        #endregion

        #region 事件注册接口

        #region PointerDown

        /// <summary>
        /// 是否注册了某名字鼠标按下回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 有</returns>
        public bool IfHasPointerDownCallback(string callbackName) {
            return _pointerDownCallbackDict.ContainsKey(callbackName);
        }

        /// <summary>
        /// 是否没有注册某名字鼠标按下回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 没有</returns>
        public bool IfNoPointerDownCallback(string callbackName) {
            return !IfHasPointerDownCallback(callbackName);
        }

        /// <summary>
        /// 设置按下回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <param name="callback">回调方法</param>
        /// <param name="isReplace">是否强制覆盖旧回调</param>
        public void SetPointerDownCallback(string callbackName, Action<PointerEventData> callback, bool isReplace = false) {

            if (_pointerDownCallbackDict.ContainsKey(callbackName)) {

                if (isReplace) {

                    if (callback == null) {

                        Debug.LogWarning("Panel: " + Name + " SetPointerDownCallback warning, callback " + callbackName + " want to set a null callback.");
                    }

                    _pointerDownCallbackDict[callbackName] = callback;
                } else {

                    Debug.LogError("Panel: " + Name + " SetPointerDownCallback failed, callback " + callbackName + " has already been set.");
                }
            } else {

                if(callback == null) {

                    Debug.LogWarning("Panel: " + Name + " SetPointerDownCallback warning, callback " + callbackName + " want to set a null callback.");
                }

                _pointerDownCallbackDict.Add(callbackName, callback);
            }
        }

        /// <summary>
        /// 移除按下回调
        /// </summary>
        public void RemovePointerDownCallback(string callbackName) {

            if (_pointerDownCallbackDict.ContainsKey(callbackName)) {

                _pointerDownCallbackDict.Remove(callbackName);
            } else {

                Debug.LogError("Panel: " + Name + " RemovePointerDownCallback failed, no such callback: " + callbackName);
            }
        }

        #endregion

        #region PointerDrag

        /// <summary>
        /// 是否注册了某名字鼠标拖动回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 有</returns>
        public bool IfHasPointerDragCallback(string callbackName) {
            return _pointerDragCallbackDict.ContainsKey(callbackName);
        }

        /// <summary>
        /// 是否没有注册某名字鼠标拖动回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 没有</returns>
        public bool IfNoPointerDragCallback(string callbackName) {
            return !IfHasPointerDragCallback(callbackName);
        }

        /// <summary>
        /// 设置拖动回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <param name="callback">回调方法</param>
        /// <param name="isReplace">是否强制覆盖旧回调</param>
        public void SetPointerDragCallback(string callbackName, Action<PointerEventData> callback, bool isReplace = false) {

            if (_pointerDragCallbackDict.ContainsKey(callbackName)) {

                if (isReplace) {

                    if (callback == null) {

                        Debug.LogWarning("Panel: " + Name + " SetPointerDragCallback warning, callback " + callbackName + " want to set a null callback.");
                    }

                    _pointerDragCallbackDict[callbackName] = callback;
                } else {

                    Debug.LogError("Panel: " + Name + " SetPointerDragCallback failed, callback " + callbackName + " has already been set.");
                }
            } else {

                if (callback == null) {

                    Debug.LogWarning("Panel: " + Name + " SetPointerDragCallback warning, callback " + callbackName + " want to set a null callback.");
                }

                _pointerDragCallbackDict.Add(callbackName, callback);
            }
        }

        /// <summary>
        /// 移除拖动回调
        /// </summary>
        public void RemovePointerDragCallback(string callbackName) {

            if (_pointerDragCallbackDict.ContainsKey(callbackName)) {

                _pointerDragCallbackDict.Remove(callbackName);
            } else {

                Debug.LogError("Panel: " + Name + " RemovePointerDragCallback failed, no such callback: " + callbackName);
            }
        }

        #endregion

        #region PointerUp

        /// <summary>
        /// 是否注册了某名字鼠标抬起回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 有</returns>
        public bool IfHasPointerUpCallback(string callbackName) {
            return _pointerUpCallbackDict.ContainsKey(callbackName);
        }

        /// <summary>
        /// 是否没有注册某名字鼠标抬起回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 没有</returns>
        public bool IfNoPointerUpCallback(string callbackName) {
            return !IfHasPointerUpCallback(callbackName);
        }

        /// <summary>
        /// 设置抬起回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <param name="callback">回调方法</param>
        /// <param name="isReplace">是否强制覆盖旧回调</param>
        public void SetPointerUpCallback(string callbackName, Action<PointerEventData> callback, bool isReplace = false) {

            if (_pointerUpCallbackDict.ContainsKey(callbackName)) {

                if (isReplace) {

                    if (callback == null) {

                        Debug.LogWarning("Panel: " + Name + " SetPointerUpCallback warning, callback " + callbackName + " want to set a null callback.");
                    }

                    _pointerUpCallbackDict[callbackName] = callback;
                } else {

                    Debug.LogError("Panel: " + Name + " SetPointerUpCallback failed, callback " + callbackName + " has already been set.");
                }
            } else {

                if (callback == null) {

                    Debug.LogWarning("Panel: " + Name + " SetPointerUpCallback warning, callback " + callbackName + " want to set a null callback.");
                }

                _pointerUpCallbackDict.Add(callbackName, callback);
            }
        }

        /// <summary>
        /// 移除抬起回调
        /// </summary>
        public void RemovePointerUpCallback(string callbackName) {

            if (_pointerUpCallbackDict.ContainsKey(callbackName)) {

                _pointerUpCallbackDict.Remove(callbackName);
            } else {

                Debug.LogError("Panel: " + Name + " RemovePointerUpCallback failed, no such callback: " + callbackName);
            }
        }

        #endregion

        #region PointerClick

        /// <summary>
        /// 是否注册了某名字鼠标点击回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 有</returns>
        public bool IfHasPointerClickCallback(string callbackName) {
            return _pointerClickCallbackDict.ContainsKey(callbackName);
        }

        /// <summary>
        /// 是否没有注册某名字鼠标点击回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 没有</returns>
        public bool IfNoPointerClickCallback(string callbackName) {
            return !IfHasPointerClickCallback(callbackName);
        }

        /// <summary>
        /// 设置点击回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <param name="callback">回调方法</param>
        /// <param name="isReplace">是否强制覆盖旧回调</param>
        public void SetPointerClickCallback(string callbackName, Action<PointerEventData> callback, bool isReplace = false) {

            if (_pointerClickCallbackDict.ContainsKey(callbackName)) {

                if (isReplace) {

                    if (callback == null) {

                        Debug.LogWarning("Panel: " + Name + " SetPointerClickCallback warning, callback " + callbackName + " want to set a null callback.");
                    }

                    _pointerClickCallbackDict[callbackName] = callback;
                } else {

                    Debug.LogError("Panel: " + Name + " SetPointerClickCallback failed, callback " + callbackName + " has already been set.");
                }
            } else {

                if (callback == null) {

                    Debug.LogWarning("Panel: " + Name + " SetPointerClickCallback warning, callback " + callbackName + " want to set a null callback.");
                }

                _pointerClickCallbackDict.Add(callbackName, callback);
            }
        }

        /// <summary>
        /// 移除点击回调
        /// </summary>
        public void RemovePointerClickCallback(string callbackName) {

            if (_pointerClickCallbackDict.ContainsKey(callbackName)) {

                _pointerClickCallbackDict.Remove(callbackName);
            } else {

                Debug.LogError("Panel: " + Name + " RemovePointerClickCallback failed, no such callback: " + callbackName);
            }
        }

        #endregion

        #region PointerEnter

        /// <summary>
        /// 是否注册了某名字鼠标进入回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 有</returns>
        public bool IfHasPointerEnterCallback(string callbackName) {
            return _pointerEnterCallbackDict.ContainsKey(callbackName);
        }

        /// <summary>
        /// 是否没有注册某名字鼠标进入回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 没有</returns>
        public bool IfNoPointerEnterCallback(string callbackName) {
            return !IfHasPointerEnterCallback(callbackName);
        }

        /// <summary>
        /// 设置鼠标进入回调，移动端一般不用可无视
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <param name="callback">回调方法</param>
        /// <param name="isReplace">是否强制覆盖旧回调</param>
        public void SetPointerEnterCallback(string callbackName, Action<PointerEventData> callback, bool isReplace = false) {

            if (_pointerEnterCallbackDict.ContainsKey(callbackName)) {

                if (isReplace) {

                    if (callback == null) {

                        Debug.LogWarning("Panel: " + Name + " SetPointerEnterCallback warning, callback " + callbackName + " want to set a null callback.");
                    }

                    _pointerEnterCallbackDict[callbackName] = callback;
                } else {

                    Debug.LogError("Panel: " + Name + " SetPointerEnterCallback failed, callback " + callbackName + " has already been set.");
                }
            } else {

                if (callback == null) {

                    Debug.LogWarning("Panel: " + Name + " SetPointerEnterCallback warning, callback " + callbackName + " want to set a null callback.");
                }

                _pointerEnterCallbackDict.Add(callbackName, callback);
            }
        }

        /// <summary>
        /// 移除鼠标进入回调
        /// </summary>
        public void RemovePointerEnterCallback(string callbackName) {

            if (_pointerEnterCallbackDict.ContainsKey(callbackName)) {

                _pointerEnterCallbackDict.Remove(callbackName);
            } else {

                Debug.LogError("Panel: " + Name + " RemovePointerEnterCallback failed, no such callback: " + callbackName);
            }
        }

        #endregion

        #region PointerExit

        /// <summary>
        /// 是否注册了某名字鼠标离开回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 有</returns>
        public bool IfHasPointerExitCallback(string callbackName) {
            return _pointerExitCallbackDict.ContainsKey(callbackName);
        }

        /// <summary>
        /// 是否没有注册某名字鼠标离开回调
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <returns>true 没有</returns>
        public bool IfNoPointerExitCallback(string callbackName) {
            return !IfHasPointerExitCallback(callbackName);
        }

        /// <summary>
        /// 设置鼠标离开回调，移动端一般不用可无视
        /// </summary>
        /// <param name="callbackName">回调名</param>
        /// <param name="callback">回调方法</param>
        /// <param name="isReplace">是否强制覆盖旧回调</param>
        public void SetPointerExitCallback(string callbackName, Action<PointerEventData> callback, bool isReplace = false) {

            if (_pointerExitCallbackDict.ContainsKey(callbackName)) {

                if (isReplace) {

                    if (callback == null) {

                        Debug.LogWarning("Panel: " + Name + " SetPointerExitCallback warning, callback " + callbackName + " want to set a null callback.");
                    }

                    _pointerExitCallbackDict[callbackName] = callback;
                } else {

                    Debug.LogError("Panel: " + Name + " SetPointerExitCallback failed, callback " + callbackName + " has already been set.");
                }
            } else {

                if (callback == null) {

                    Debug.LogWarning("Panel: " + Name + " SetPointerExitCallback warning, callback " + callbackName + " want to set a null callback.");
                }

                _pointerExitCallbackDict.Add(callbackName, callback);
            }
        }

        /// <summary>
        /// 移除鼠标离开回调，移动端一般不用可无视
        /// </summary>
        public void RemovePointerExitCallback(string callbackName) {

            if (_pointerExitCallbackDict.ContainsKey(callbackName)) {

                _pointerExitCallbackDict.Remove(callbackName);
            } else {

                Debug.LogError("Panel: " + Name + " RemovePointerExitCallback failed, no such callback: " + callbackName);
            }
        }

        #endregion

        #endregion

        #region UI事件相关函数

        public virtual void OnPointerDown(PointerEventData eventData) {
//#if UNITY_EDITOR
//            Debug.Log("UGUI Name " + Name + " <color=#ff0000>OnPointerDown</color> has been called.");
//#endif
            foreach (var kv in _pointerDownCallbackDict) {

                if(kv.Value != null) {

                    kv.Value(eventData);
                }
            }
        }

        public virtual void OnDrag(PointerEventData eventData) {
//#if UNITY_EDITOR
//            Debug.Log("UGUI Name " + Name + " <color=#ff0000>OnDrag</color> has been called.");
//#endif
            foreach (var kv in _pointerDragCallbackDict) {

                if (kv.Value != null) {

                    kv.Value(eventData);
                }
            }
        }

        public virtual void OnPointerUp(PointerEventData eventData) {
//#if UNITY_EDITOR
//            Debug.Log("UGUI Name " + Name + " <color=#ff0000>OnPointerUp</color> has been called.");
//#endif
            foreach (var kv in _pointerUpCallbackDict) {

                if (kv.Value != null) {

                    kv.Value(eventData);
                }
            }
        }

        public virtual void OnPointerClick(PointerEventData eventData) {
//#if UNITY_EDITOR
//            Debug.Log("UGUI Name " + Name + " <color=#ff0000>OnPointerClick</color> has been called.");
//#endif
            foreach (var kv in _pointerClickCallbackDict) {

                if (kv.Value != null) {

                    kv.Value(eventData);
                }
            }
        }

        public virtual void OnPointerEnter(PointerEventData eventData) {
//#if UNITY_EDITOR
//            Debug.Log("UGUI Name " + Name + " <color=#ff0000>OnPointerEnter</color> has been called.");
//#endif
            foreach (var kv in _pointerEnterCallbackDict) {

                if (kv.Value != null) {

                    kv.Value(eventData);
                }
            }
        }

        public virtual void OnPointerExit(PointerEventData eventData) {
//#if UNITY_EDITOR
//            Debug.Log("UGUI Name " + Name + " <color=#ff0000>OnPointerExit</color> has been called.");
//#endif
            foreach (var kv in _pointerExitCallbackDict) {

                if (kv.Value != null) {

                    kv.Value(eventData);
                }
            }
        }

        #endregion
    }
}
